package com.ly.component.threadpool.util;

import com.ly.model.Tuple;
import com.ly.utils.MyBooleanUtil;
import com.ly.utils.MyCollectionUtil;
import lombok.Getter;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

public class PeriodTaskPool {
	private final SpringTaskManager springTaskManager = SpringTaskManager.getInstance();
	private final String TASK_NAME = getClass().getName();
	@Getter
	private final Map<String, Function<Map<String, Object>, Boolean>> handlers = new HashMap<>();

	private PeriodTaskPool() {

	}

	public static PeriodTaskPool getInstance() {
		return Instance.DEFAULT.periodTaskPool;
	}

	public void start() {
		trigger();
	}

	public void submitHandler(String name, Function<Map<String, Object>, Boolean> handler) {
		synchronized (handlers) {
			handlers.put(name, handler);
		}
		trigger();
	}

	public void cancelHandler(String name) {
		synchronized (handlers) {
			handlers.remove(name);
		}
	}

	public void submitClassNameHandler(String name, Function<Map<String, Object>, Boolean> handler) {
		submitHandler(String.format("%s[%s]", Thread.currentThread().getStackTrace()[1].getClassName(), name), handler);
	}

	public void cancelClassNameHandler(String name, Function<Map<String, Object>, Boolean> handler) {
		cancelHandler(name);
	}

	private void trigger() {
		process();
	}

	private void process() {
		springTaskManager.submit(TASK_NAME, new ConcurrentHashMap<>(), p -> {
			int retry = 0;
			while (true) {
				if (MyCollectionUtil.isEmpty(handlers)) {
					retry++;
					if (retry > 5) {
						break;
					} else {
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						continue;
					}
				}
				List<Tuple<String, Function<Map<String, Object>, Boolean>>> handlerTuples;
				synchronized (handlers) {
					handlerTuples = handlers.entrySet().parallelStream()
											.map(entry -> new Tuple<>(entry.getKey(), entry.getValue()))
											.collect(Collectors.toList());
				}
				handlerTuples.parallelStream()
							 .forEach(tuple -> {
								 Function<Map<String, Object>, Boolean> h = tuple.getRight();
								 if (!MyBooleanUtil.isTrue(h.apply(p))) {
									 cancelHandler(tuple.getLeft());
								 }
							 });
			}
			return true;
		}, params -> true);
	}


	enum Instance {
		DEFAULT(new PeriodTaskPool());

		private PeriodTaskPool periodTaskPool;

		Instance(PeriodTaskPool periodTaskPool) {
			this.periodTaskPool = periodTaskPool;
		}
	}
}
